package com.autumn.sms.service.core.impl;

import java.util.Date;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import com.autumn.redis.AutumnRedisTemplate;
import com.autumn.sms.SmsEventData;
import com.autumn.sms.service.SmsSendException;
import com.autumn.sms.service.consts.RedisKeyConsts;
import com.autumn.sms.service.consts.ServiceConsts;
import com.autumn.sms.service.core.ISmsDispatchService;
import com.autumn.sms.service.core.ISmsPlatformService;
import com.autumn.sms.service.entities.mongodb.AbstractSendData;
import com.autumn.sms.service.entities.mongodb.SendFailData;
import com.autumn.sms.service.entities.mongodb.SendSuccessData;
import com.autumn.sms.service.services.ISendLogService;
import com.autumn.sms.service.services.ISmsAppTemplateService;
import com.autumn.sms.service.vo.PlatformTemplateValue;
import com.autumn.sms.service.vo.SendTemplateValue;
import com.autumn.sms.service.vo.StandardTemplateValue;
import com.autumn.util.DateUtils;
import com.autumn.util.ExceptionUtils;
import com.autumn.util.StringUtils;
import com.autumn.util.tuple.TupleThree;
import com.autumn.util.tuple.TupleTwo;

/**
 * 调度服务
 * 
 * @author 老码农
 *
 *         2018-01-12 19:36:04
 */
@Service
public class SmsDispatchServiceImpl implements ISmsDispatchService {

	private final static Log logger = LogFactory.getLog(SmsDispatchServiceImpl.class);

	@Autowired
	private ApplicationContext applicationContext;

	@Autowired
	private ISmsAppTemplateService smsAppTemplateService;

	@Autowired
	private AutumnRedisTemplate autumnRedisTemplate;

	@Autowired
	private ISendLogService sendLogService;

	private TupleTwo<SendTemplateValue, StandardTemplateValue> check(SmsEventData eventData) {
		ExceptionUtils.checkNotNull(eventData, "eventData");
		if (StringUtils.isNullOrBlank(eventData.getServiceId())) {
			ExceptionUtils.throwValidationException("请求服务id为 null 或空白值。");
		}
		if (eventData.getIsVerificationCode()) {
			if (eventData.getVerificationCodeType() == null) {
				ExceptionUtils.throwValidationException("发送验证码时，必须包含验证码类型。");
			}
		} else {
			if (StringUtils.isNullOrBlank(eventData.getTemplateCode())) {
				ExceptionUtils.throwValidationException("请求 templateCode 为 null 或空白值。");
			}
		}
		SendTemplateValue sendTemplate = smsAppTemplateService.getSendTemplate(eventData.getServiceId());
		if (sendTemplate == null) {
			ExceptionUtils.throwValidationException("服务Id:" + eventData.getServiceId() + " 无权发送。");
		}
		StandardTemplateValue standardTemplate;
		if (eventData.getIsVerificationCode()) {
			standardTemplate = sendTemplate
					.findVerificationCodeTemplate(eventData.getVerificationCodeType().intValue());
			if (standardTemplate == null) {
				ExceptionUtils.throwValidationException(
						"服务Id:" + eventData.getServiceId() + " 未配置验证类型[" + eventData.getVerificationCodeType() + "]");
			}
			eventData.setTemplateCode(standardTemplate.getTemplateCode());
		} else {
			standardTemplate = sendTemplate.getTemplates().get(eventData.getTemplateCode());
			if (standardTemplate == null) {
				ExceptionUtils.throwValidationException(
						"服务Id:" + eventData.getServiceId() + " 未配置模板[" + eventData.getTemplateCode() + "]");
			}
		}
		if (standardTemplate.getPlatforms() == null || standardTemplate.getPlatforms().size() == 0) {
			ExceptionUtils.throwValidationException(
					"服务Id:" + eventData.getServiceId() + " 的模板[" + eventData.getTemplateCode() + "] 未配置任可发送平台。");
		}
		standardTemplate.check(eventData.getParams());
		return new TupleTwo<>(sendTemplate, standardTemplate);
	}

	private String getMobilePhoneLimitKey(String serviceId, String mobilePhone) {
		return String.format("%s%s_%s", RedisKeyConsts.MOBILE_PHONE_SEND_LIMIT_KEY_PREFIX, serviceId.toUpperCase(),
				mobilePhone);
	}

	private TupleThree<SendTemplateValue, StandardTemplateValue, PlatformTemplateValue> sendSms(SmsEventData eventData)
			throws Exception {
		TupleTwo<SendTemplateValue, StandardTemplateValue> item = this.check(eventData);
		StandardTemplateValue standardTemplate = item.getItem2();
		String key = null;
		boolean isRestrict = standardTemplate.getIsRestrict() && standardTemplate.getRestrictSeconds() != null;
		if (isRestrict) {
			key = getMobilePhoneLimitKey(eventData.getServiceId(), eventData.getMobilePhone());
			String value = autumnRedisTemplate.getString(key);
			if (value != null) {
				/*
				 * long diffSeconds = (System.currentTimeMillis() - value) / 1000L; if
				 * (diffSeconds <= 0L) { autumnRedisTemplate.delete(key); } else { long diff =
				 * standardTemplate.getRestrictSeconds() - diffSeconds;
				 * autumnRedisTemplate.set(key, System.currentTimeMillis(), diff,
				 * TimeUnit.SECONDS); }
				 */
				throw new SmsSendException(false, false,
						"在限定的 " + standardTemplate.getRestrictSeconds() + " 秒内调用超过次数过多。");
			}
		}
		Exception error = null;
		for (PlatformTemplateValue platformTemplate : standardTemplate.getPlatforms()) {
			try {
				String beanName = ServiceConsts.Platform.BEAN_NAME_PREFIX
						+ platformTemplate.getPlatformCode().toLowerCase();
				ISmsPlatformService platform = null;
				try {
					platform = applicationContext.getBean(beanName, ISmsPlatformService.class);
				} catch (Exception e) {
					logger.error("无平台 [" + platformTemplate.getPlatformCode() + "] 的实现。");
					continue;
				}
				platform.send(platformTemplate, eventData);
				if (isRestrict) {
					try {
						autumnRedisTemplate.set(key, DateUtils.dateFormat(new Date()),
								(long) standardTemplate.getRestrictSeconds(), TimeUnit.SECONDS);
					} catch (Exception e) {
						logger.error(e.getMessage(), e);
					}
				}
				return new TupleThree<>(item.getItem1(), standardTemplate, platformTemplate);
			} catch (Exception e) {
				error = e;
				logger.error("platform:" + platformTemplate.getPlatformCode() + " msg:" + e.getMessage(), e);
			}
		}
		throw error;
	}

	@Override
	public void send(SmsEventData eventData) {
		boolean isSendFail = true;
		try {
			TupleThree<SendTemplateValue, StandardTemplateValue, PlatformTemplateValue> ptv = sendSms(eventData);
			if (ptv != null) {
				isSendFail = false;
				sendLogService.saveSuccess(createSuccessData(ptv, eventData));
			}
		} catch (Exception e) {
			if (isSendFail) {
				sendLogService.saveFail(createFailData(e, eventData));
			} else {
				logger.error(e.getMessage(), e);
			}
		}
	}

	private SendSuccessData createSuccessData(
			TupleThree<SendTemplateValue, StandardTemplateValue, PlatformTemplateValue> ptv, SmsEventData eventData) {
		SendSuccessData result = new SendSuccessData();
		setSendData(result, eventData);
		result.setServiceName(ptv.getItem1().getServideName());
		result.setTemplateCode(ptv.getItem2().getTemplateCode());
		result.setTemplateName(ptv.getItem2().getTemplateName());
		result.setPlatformCode(ptv.getItem3().getPlatformCode());
		result.setPlatformName(ptv.getItem3().getPlatformName());
		return result;
	}

	private SendFailData createFailData(Exception err, SmsEventData eventData) {
		SendFailData result = new SendFailData();
		setSendData(result, eventData);
		if (err instanceof SmsSendException) {
			SmsSendException sendError = (SmsSendException) err;
			result.setErrorCode(sendError.getCode());
			result.setIsSupportRepeatSend(sendError.isSupportRepeatSend());
		} else {
			result.setErrorCode(0);
			result.setIsSupportRepeatSend(false);
		}
		result.setErrorMessage(err.getMessage());
		return result;
	}

	private void setSendData(AbstractSendData data, SmsEventData eventData) {
		data.setClientIp(eventData.getClientIp());
		data.setMessageId(eventData.getMessageId());
		data.setMobilePhone(eventData.getMobilePhone());
		data.setServiceId(eventData.getServiceId());
		data.setEventTime(eventData.getEventTime());
		data.setParams(eventData.getParams());
		data.setTemplateCode(eventData.getTemplateCode());
		data.setSendTime(new Date());
		data.setServiceAddress(eventData.getServiceIp());
	}
}
